/*
 * Copyright 2010 WANdisco, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */
package com.googlecode.svnj;

import java.util.ArrayList;
import java.util.List;

public class TxDeltaWindow {
    /** The offset of the source view for this window.  */
    //svn_filesize_t sview_offset; (apr_int64_t)
    long sview_offset;

    /** The length of the source view for this window.  */
    long sview_len;

    /** The length of the target view for this window, i.e. the number of
     * bytes which will be reconstructed by the instruction stream.  */
    long tview_len;

    /** The number of instructions in this window.  */
    int num_ops;

    /** The number of svn_txdelta_source instructions in this window. If
     * this number is 0, we don't need to read the source in order to
     * reconstruct the target view.
     */
    int src_ops;

    /** The instructions for this window.  */
    //const svn_txdelta_op_t *ops;
    //TxDeltaOp[] ops;
    List<TxDeltaOp> ops;

    /** New data, for use by any `svn_txdelta_new' instructions.  */
    //const svn_string_t *new_data;
    //String[] newData;
    List<byte[]> newData;
    
    public TxDeltaWindow(long sview_offset, long sview_len, long tview_len, int num_ops, int src_ops) {
        this.sview_offset = sview_offset;
        this.sview_len = sview_len;
        this.tview_len = tview_len;
        this.num_ops = num_ops;
        this.src_ops = src_ops;
        ops = new ArrayList<TxDeltaOp>();
        newData = new ArrayList<byte[]>();
    }

    // aligned w/ svn_delta_action enum in svn_delta.h
    private static final int OP_SOURCE = 0;
    private static final int OP_TARGET = 1;
    private static final int OP_NEW = 2;
    /* called from native code */
    private void addDeltaOp(int op, int offset, int len)  {
        TxDeltaOpType type;
        switch (op) {
        case OP_SOURCE: type = TxDeltaOpType.SOURCE; break;
        case OP_TARGET: type = TxDeltaOpType.TARGET; break;
        case OP_NEW: type = TxDeltaOpType.NEW; break;
        default:
            throw new IllegalArgumentException(
                    "invalid op type " + op
                    );
        }
        TxDeltaOp opobj = new TxDeltaOp(type,offset,len);
        p("addDeltaOp(" + opobj + ")");
        ops.add(opobj);
    }
    /* called from native code */
    private void addData(byte[] data) {
        if (data != null) {
            p("addData(" + data.length + ")");
            newData.add(data);
        } else {
            p("addData(NULL)");
        }
    }
    private static String trunc(String s) {
        if (s.length() > 50) {
            s = s.substring(0, 47) + "...";
        }
        return s;
    }
    public String toString() {
        return "[TxDeltaWindow: num_ops=" + num_ops + " ops=" + ops
        + " datasize=" + newData.size() + "]";
    }
    /* called from native code */
    private static TxDeltaWindow createWindow(long sview_offset, long sview_len,
            long tview_len, int num_ops, int src_ops) {
        p("create window(" + sview_offset + "," + sview_len + "," + tview_len + "," + num_ops
                    + "," + src_ops + ")");
        TxDeltaWindow ret = new TxDeltaWindow(
                sview_offset, sview_len, tview_len,
                num_ops, src_ops);
        return ret;
    }    
    /** a single TxDelta instruction */
    public static class TxDeltaOp {
        TxDeltaOp(TxDeltaOpType op, int offset, int len) {
            this.op = op;
            this.offset = offset;
            this.length = len;
        }
        public TxDeltaOpType op;
        /** Offset of delta, see #svn_delta_action for more details. */
        public /*apr_size_t*/int offset;
         /** Number of bytes of delta, see #svn_delta_action for more details. */
        public /*apr_size_t*/int length;
        public String toString() {
            return "[TxDeltaOp: op=" + op + " offset=" + offset + " len=" + length + "]";
        }
    }
    
    public static enum TxDeltaOpType {
        SOURCE, TARGET, NEW
    }

    private static void p(String s) {
        System.err.println("[TxDelta] " + s);
    }
    
}
